package com.thoughtworks.jspecsupport;

import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.ui.components.panels.NonOpaquePanel;
import com.thoughtworks.jspecsupport.settings.InvalidSettingsException;
import org.mozilla.javascript.tools.shell.RhinoShell;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class RunJSpecTestsAction extends AnAction {

    static final JSpecTestFilePicker specTestFilePicker = new JSpecTestFilePicker();

    public void actionPerformed(AnActionEvent event) {
        try {
            invokeTests(event);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InvalidSettingsException e) {
            Project project = event.getData(PlatformDataKeys.PROJECT);
            Messages.showMessageDialog(project, e.errors, "Error", Messages.getInformationIcon());
        } catch (JsFileNotFoundException e) {
            Project project = event.getData(PlatformDataKeys.PROJECT);
            Messages.showMessageDialog(project, e.jsFile + " not exist.", "Error", Messages.getInformationIcon());            
        }
    }

    private void invokeTests(AnActionEvent e) throws IOException {
        Project project = e.getData(PlatformDataKeys.PROJECT);
        VirtualFile file = e.getData(PlatformDataKeys.VIRTUAL_FILE);

        List<VirtualFile> testFiles = searchTestFiles(file);
        String testResult = runTestAndGetResult(testFiles, project);
        setUpRunResultView(project, testResult);
    }

    private List<VirtualFile> searchTestFiles(VirtualFile file) {
        List<VirtualFile> testFiles = new ArrayList<VirtualFile>();
        doSearchTestFiles(testFiles, file);
        return testFiles;
    }

    private void doSearchTestFiles(List<VirtualFile> foundTestFiles, VirtualFile file) {
        if (file.isDirectory()) {
            for (VirtualFile oneFile : file.getChildren()) {
                doSearchTestFiles(foundTestFiles, oneFile);                                
            }
        } else {
            if (specTestFilePicker.isMatch(file)) {
                foundTestFiles.add(file);
            }
        }
    }

    private String runTestAndGetResult(List<VirtualFile> files, Project project) throws IOException {
        RunnerGenerator generator = new RunnerGenerator();

        String generatedRunnerFileContent = generator.generate(files, project);
        System.out.println("Gennerated Runner File: " + generatedRunnerFileContent);

        String testResult = runTest(generatedRunnerFileContent);
        testResult = StringUtil.filterColor(testResult);
        return testResult;
    }

    private void setUpRunResultView(Project project, String testResult) {
        ToolWindowManager manager = ToolWindowManager.getInstance(project);
        ToolWindow run = manager.getToolWindow("Run");

        NonOpaquePanel runWindowComponent = (NonOpaquePanel) run.getComponent();
        JSPecRunPanel testResultArea = new JSPecRunPanel();
        runWindowComponent.setContent(testResultArea);

        run.setAvailable(true, null);
        run.show(null);
        testResultArea.updateTestResult(testResult);
    }

    private String runTest(String runnerJsFileContent) {
        ByteArrayOutputStream under = new ByteArrayOutputStream();
        RhinoShell shell = new RhinoShell(new PrintStream(under), new PrintStream(under));
        shell.runTest(runnerJsFileContent);
        return new String(under.toByteArray());
    }
}